using System;
using System.Collections.Generic;
using Nemerle.Collections;

class Task021 : TaskBase
{
  override public SolveInt() : int
  {
    def primes = List();
    primes.Add(2);
    primes.Add(3);

    def generatePrimes(cand, max)
    {
      | (0, _) => generatePrimes(primes[primes.Count - 1], max)
      | _ when cand > max => {}
      | _ =>
        when (primes.TrueForAll(x => cand % x != 0))
          primes.Add(cand);
        generatePrimes(cand + 2, max)
    }

    def maxValue = 10000;
    generatePrimes(0, maxValue);

    def primeFactors(l, n)
    {
      match (primes.Find(x => n % x == 0))
      {
        | 0 => l
        | x =>
          primeFactors(
            match (l)
            {
              | ((y, c) :: t) when y == x => (y, c + 1) :: t
              | _ => (x, 1) :: l
            },
            n / x)
      }
    }

    def allFactors(pf)
    {
      | (x, c) :: t =>
        def l = allFactors(t);
        mutable res = [];
        mutable p = 1;
        for (mutable i = 0; i < c + 1; i++)
        {
          res = res.Append(l.Map(_ * p));
          p *= x
        }
        res
      | _ => [ 1 ]
    }

    def sums = array(maxValue + 1);
    def sumAllRealFactors(n)
    {
      when (sums[n] == 0)
        sums[n] = allFactors(primeFactors([], n)).FoldLeft(0, _ + _) - n;
      sums[n]
    }

    def calcTotal(acc, n)
    {
      | (_, 2) => acc
      | _ =>
        calcTotal(
          acc + match (sumAllRealFactors(n))
          {
            | x when x > 0 && x <= maxValue && x != n && sumAllRealFactors(x) == n => n
            | _ => 0
          },
          n - 1)
    }
    calcTotal(0, maxValue);
  }
}
